package utils

import (
	"fmt"
	"sync/atomic"
)

type MonitorCallBackAdapter struct {
	fn func(cb GetInfoCbFunc)
}

func NewMonitorCallBackAdapter(fn func(cb GetInfoCbFunc)) *MonitorCallBackAdapter {
	rval := &MonitorCallBackAdapter{
		fn: fn,
	}
	return rval
}

func (this *MonitorCallBackAdapter) Calcu(secs float64) {

}

func (this *MonitorCallBackAdapter) Reset() {

}

func (this *MonitorCallBackAdapter) GetInfo(cb GetInfoCbFunc) {
	this.fn(cb)
}

type MonitorSpeedNTimeRec struct {
	CurrN     int64
	LastN     int64
	LastSpeed int64
	Id        string
}

func NewMonitorSpeedNTimeRec() *MonitorSpeedNTimeRec {
	rval := &MonitorSpeedNTimeRec{}
	rval.Reset()
	return rval
}

func (this *MonitorSpeedNTimeRec) Calcu(secs float64) {
	defer func() {
		this.LastN = this.CurrN
	}()
	if secs == 0 {
		return
	}

	n := this.CurrN - this.LastN
	if n == 0 {
		this.LastSpeed = 0
		return
	}
	this.LastSpeed = int64(float64(n) / secs)
	this.LastN = this.LastN
}

func (this *MonitorSpeedNTimeRec) Delta(n int64) {
	atomic.AddInt64(&this.CurrN, n)
}

func (this *MonitorSpeedNTimeRec) Reset() {
	this.CurrN = 0
	this.LastN = 0
	this.LastSpeed = 0
}

func (this *MonitorSpeedNTimeRec) GetInfo(cb GetInfoCbFunc) {
	//cb(this, this.StationId,"n", this.CurrN)
	//cb(this, this.StationId,"speed", this.LastSpeed)

	cb(this, this.Id, "io", fmt.Sprintf("%d(s) %d", this.LastSpeed, this.CurrN))

}

func (this *MonitorSpeedNTimeRec) SpeedIO() string {
	return fmt.Sprintf("%d(s) %d", this.LastSpeed, this.CurrN)
}

func (this *MonitorSpeedNTimeRec) Info() string {
	return fmt.Sprintf("%d(s) %d", this.LastSpeed, this.CurrN)
}

type MonitorSpeedSizeRec struct {
	CurrSize      int64
	LastSize      int64
	LastSpeedSize int64
	CurrN         int64
	LastN         int64
	LastSpeedN    int64

	LastSpeedCalcuInfo string
	Id                 string
}

func NewMonitorSpeedSizeRec() *MonitorSpeedSizeRec {
	rval := &MonitorSpeedSizeRec{}
	rval.Reset()
	return rval
}

func (this *MonitorSpeedSizeRec) Delta(n int64) {
	atomic.AddInt64(&this.CurrSize, n)
	atomic.AddInt64(&this.CurrN, 1)
}

func (this *MonitorSpeedSizeRec) DeltaBuf(data []byte) {
	this.Delta(int64(len(data)))
}

func (this *MonitorSpeedSizeRec) Calcu(secs float64) {
	defer func() {
		this.LastSize = this.CurrSize
		this.LastN = this.CurrN
	}()
	if secs == 0 {
		return
	}
	n := this.CurrN - this.LastN
	if n == 0 {
		this.LastSpeedN = 0
		this.LastSpeedSize = 0
		return
	}
	size_v := this.CurrSize - this.LastSize
	this.LastSpeedCalcuInfo = fmt.Sprintf("n %d, size:%d sec: %.2f", n, size_v, secs)
	this.LastSpeedN = int64(float64(n) / secs)
	this.LastSpeedSize = int64(float64(size_v) / secs)
}

func (this *MonitorSpeedSizeRec) Reset() {
	this.CurrN = 0
	this.LastN = 0
	this.LastSpeedN = 0

	this.CurrSize = 0
	this.LastSize = 0
	this.LastSpeedSize = 0
}

func (this *MonitorSpeedSizeRec) SpeedIO() string {
	return fmt.Sprintf("%d(s) %d", this.LastSpeedN, this.CurrN)
}

func (this *MonitorSpeedSizeRec) SpeedInfo() string {
	return fmt.Sprintf("size: %s /s %s, io:%d(s) %d", HumanFilesize(this.LastSpeedSize), HumanFilesize(this.CurrSize), this.LastSpeedN, this.CurrN)
}

func (this *MonitorSpeedSizeRec) Info() string {
	return fmt.Sprintf("size: %s(s) %s, io:%d(s) %d", HumanFilesize(this.LastSpeedSize), HumanFilesize(this.CurrSize), this.LastSpeedN, this.CurrN)
}

func (this *MonitorSpeedSizeRec) SizeInfo() string {
	return fmt.Sprintf("%d(n) %s",
		this.CurrN, HumanFilesize(this.CurrSize))
}

func (this *MonitorSpeedSizeRec) SpeedSize() string {
	return fmt.Sprintf("%s(s) %s",
		HumanFilesize(this.LastSpeedSize), HumanFilesize(this.CurrSize))
}

func (this *MonitorSpeedSizeRec) GetInfo(cb GetInfoCbFunc) {
	cb(this, this.Id, "io", this.SpeedIO())
	cb(this, this.Id, "size", this.SpeedSize())

	//cb(this, this.StationId, "n", this.CurrN)
	//cb(this, this.StationId,"speed", this.LastSpeedN)
	//
	//cb(this, this.StationId,"size", this.CurrSize)
	//cb(this, this.StationId,"speedsize", this.LastSpeedSize)
}
